package com.lizhi.menu.common.handler;

import cn.dev33.satoken.exception.NotLoginException;
import com.lizhi.menu.common.entity.ApplicationException;
import com.lizhi.menu.common.enums.ResultCode;
import com.lizhi.menu.common.response.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * Description: 验值错误异常处理器
 *
 * @author lizhi
 */
@Slf4j
@Component
@RestControllerAdvice
public class ValidatedExceptionHandle {

    /**
     * 校验错误拦截处理
     *
     * @param exception 错误信息集合
     * @return 错误信息
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object validationBodyException(MethodArgumentNotValidException exception) {
        BindingResult result = exception.getBindingResult();
        if (result.hasErrors()) {
            List<ObjectError> errors = result.getAllErrors();
            List<String> errorMsgs = new ArrayList<>();
            errors.forEach(p -> {
                FieldError error = (FieldError) p;

                log.error("Request verify failure: Object { "
                        + error.getObjectName()
                        + " }, Field { "
                        + error.getField()
                        + " }, Message { "
                        + error.getDefaultMessage()
                        + " } ");
                errorMsgs.add(error.getDefaultMessage());
            });
            String join = String.join("，", errorMsgs);
            return Result.failure(ResultCode.FAILURE.getCode(), join);
        }
        return Result.failure(ResultCode.FAILURE.getCode(), "数据校验失败,请检查提交数据");
    }

    /**
     * 校验错误拦截处理
     *
     * @param exception 错误信息集合
     * @return 错误信息
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Object validationParamsException(ConstraintViolationException exception) {
        Set<ConstraintViolation<?>> violations = exception.getConstraintViolations();
        List<ErrorValue> errors = new ArrayList<>();
        for (ConstraintViolation<?> cv : violations) {
            String field = cv.getPropertyPath().toString();
            String message = cv.getMessage();
            Object value = cv.getInvalidValue();
            errors.add(new ErrorValue(field, message, value));
        }
        return Result.failure(ResultCode.FAILURE.getCode(), "数据校验失败,请检查提交数据", errors);
    }

    /**
     * 参数类型转换错误
     *
     * @param exception 错误
     * @return 错误信息
     */
    @ExceptionHandler(HttpMessageConversionException.class)
    public Object parameterTypeException(HttpMessageConversionException exception) {
        String message = exception.getLocalizedMessage();
        log.error(message);
        return Result.failure(400, ObjectUtils.isEmpty(message) ? "数据类型不正确" : message);
    }


    /**
     * 处理自定义异常
     *
     * @param ex ApplicationException
     * @return HttpResponse
     */
    @ExceptionHandler(ApplicationException.class)
    public Result<Void> handleApplicationException(ApplicationException ex) {
        return Result.failure(ex.getResponseCode().getCode(), ex.getMessage());
    }

    /**
     * token错误拦截
     *
     * @param nle
     * @description: errorHandle
     * @author: xian
     * @date: 2022-10-31 15:00
     * @return: HttpResponse
     */
    @ExceptionHandler(NotLoginException.class)
    public Result<Object> handlerNotLoginException(NotLoginException nle) {
        // 不同异常返回不同状态码
        String message = "";
        if (nle.getType().equals(NotLoginException.NOT_TOKEN)) {
            message = "请登录后再进行操作";
        } else if (nle.getType().equals(NotLoginException.INVALID_TOKEN)) {
            message = "登录信息已过期，请重新登录";
        } else if (nle.getType().equals(NotLoginException.TOKEN_TIMEOUT)) {
            message = "登录信息已过期，请重新登录";
        } else if (nle.getType().equals(NotLoginException.BE_REPLACED)) {
            message = "您的账户已在另一台设备上登录，如非本人操作，请立即修改密码";
        } else if (nle.getType().equals(NotLoginException.KICK_OUT)) {
            message = "已被系统强制下线";
        } else {
            message = "当前会话未登录";
        }
        // 返回给前端
        return Result.failure(ResultCode.TOKEN_EXCEED.getCode(), message);
    }


}
